/*
 * File:   File.h
 * Author: Stripped
 *
 * Created on May 24, 2009, 8:47 AM
 */

#ifndef _FILE_H
#define _FILE_H

#include <fstream>
#include <string>
#include <sstream>
#include "KeyValueEntity.h"
#include <stdio.h>
#include <stdlib.h>

using namespace std;

class File
{
public:
        File(string path)
        {
            this->path = path;
        }

        void openOrCreate()
        {
        	ios::openmode mode = ios::app | ios::in | ios::out | ios::binary;
        	m_file.open(path.c_str(),mode);

            if (!this->m_file.is_open() || this->m_file.fail())
            {
                this->m_file.clear();
                throw ios_base::failure("No es posible abrir el archivo.");
            }
        }

        void seekStart()
        {
            m_file.seekg(0, ios_base::beg);
            m_file.seekp(0, ios_base::beg);
        }

        void close()
        {
            this->m_file.close();
        }

        bool eof()
        {
            return (m_file.eof() || m_file.fail());
        }

        void setLength(unsigned int size)
        {
            this->m_file.clear();
            this->seekStart();
            this->m_file.write((char*)&size, sizeof(unsigned int));
        }

        unsigned int readLength()
        {
            unsigned int result;
            this->seekStart();
            this->m_file.read((char*)&result, sizeof(unsigned int));
            return result;
        }

        ~File()
        {
            if (this->m_file.is_open())
            {
                this->close();
            }
        }

        template <typename TKey, typename TValue>
        void save(const KeyValuePair<TKey, TValue> record)
        {
            m_file.write((char*)&record.key, sizeof(TKey));
            m_file.write((char*)&record.value, sizeof(TValue));
        }

        template <typename TKey, typename TValue>
        void readNext(KeyValuePair<TKey, TValue>* record)
        {
            m_file.read((char*)&record->key, sizeof(TKey));
            m_file.read((char*)&record->value, sizeof(TValue));
        }

        template <typename TValue>
        void save(const KeyValuePair<string, TValue> record)
        {
            this->saveString(record.key);
            m_file.write((char*)&record.value, sizeof(TValue));
        }

        template <typename TKey>
        void save(const KeyValuePair<TKey, string> record)
        {
            m_file.write((char*)&record.key, sizeof(TKey));
            this->saveString(record.value);
        }

        //template < >
        void save(const KeyValuePair<string, string> record)
        {
            this->saveString(record.key);
            this->saveString(record.value);
        }

        template <typename TValue>
        void readNext(KeyValuePair<string, TValue>* record)
        {
            record->key = this->readString();

            m_file.read((char*)&record->value,sizeof(TValue));
        }

        template <typename TKey>
        void readNext(KeyValuePair<TKey, string>* record)
        {
            m_file.read((char*)&record->key,sizeof(TKey));

            record->value = this->readString();
        }

        void readNext(KeyValuePair<string, string>* record)
        {
            record->key = this->readString();
            record->value = this->readString();
        }

        string getPath()
        {
            return this->path;
        }

private:
        fstream m_file;

        // TODO: remove when fixed
        //stringstream m_file;

        string path;

        string readString();/*
        {
            unsigned int size = 0;
            char* buffer = NULL;
            string result;

            m_file.read((char*)&size,sizeof(unsigned int));

            buffer = new char [size + 1];

            for (unsigned int i = 0; i <= size; i++)
            {
                buffer[i] = '\0';
            }

            m_file.read(buffer, size);

            result = string(buffer);
            delete[] buffer;

            return result;
        }*/

        void saveString(string element);/*
        {
            unsigned int size = (unsigned int)element.size();
            m_file.write((char*)&size, sizeof(unsigned int));
            m_file.write(element.c_str(), element.size());
        }*/

        File(const File& file);
        File& operator=(const File& file);
};

#endif  /* _FILE_H */
